/**
 * @file BluetoothTransparentModule.h
 * @author your name (you@domain.com)
 * @brief 蓝牙透传模块
 * @version 0.1
 * @date 2023-06-27
 * 
 * @copyright Copyright (c) 2005-2023 XAG Co., Ltd. All Rights Reserved
 * 
 */

#include <limits.h>
#include <iostream>
#include <fstream>
#include <cstdio>
#include <iomanip>
#include <future>  /* NOLINT */
#include <thread>  /* NOLINT */
#include <memory>
#include <functional>
#include <chrono>  /* NOLINT */
#include <vector>
#include <utility>

#include "BluetoothTransparentModule_Impl.h"
#include "SystemCalls.h"
#include "XAG_SerialPort.h"


using namespace business_modules_xnetcomm;  // NOLINT
using namespace kapok_hardware;             // NOLINT
using std::string;

namespace business_modules_bluetoothtransparent {

#define XNET_MAX_SEND_NUMBER 500

string strServerName1 = XNET_SRV_BLUETOOTH_TRANS_OPERATION;     // NOLINT
string strServerName2 = XNET_SERVER_NODE_NAME_DLS;              // NOLINT
kapok_hardware::XAG_SerialPort *sdev = nullptr;

/**
 * BluetoothSendReceive - bluetooth at instructions send and receive.
 * @at_instruction          : at instruction
 * @instruction_exec_status : comparison value
 */
int32_t BluetoothSendReceive(char * pAtInstruction, char *pAtExecStatus) {
    char pRecvBuff[BT_BUFFER_LEN] = {0};
    int32_t s32Ret = 0;

    sdev->Write(pAtInstruction, strlen(pAtInstruction));
    usleep(10*1000);

    s32Ret = sdev->Read(pRecvBuff, BT_BUFFER_LEN);
    XAG_LOG_I("--- uart receive len=%d:[%s]", s32Ret, pRecvBuff);
    if (strstr(pRecvBuff, pAtExecStatus) != NULL) {
        return 0;
    }

    return -1;
}

/**
 * BluetoothAtMode - entry AT mode.
 * @none
 */
int32_t BluetoothAtMode(void) {
    if (BluetoothSendReceive(const_cast<char*>(BT_ENTER_AT), const_cast<char*>(AT_INSTRUCTION_OK)) == 0) {
        XAG_LOG_I("info : AT mode config success.\n");
    } else {
        XAG_LOG_I("[[ error: AT mode version config fail...]]\r\n");
        return -1;
    }

    return 0;
}

/**
 * BluetoothChipVersion - get chip version.
 * @none
 */
int32_t BluetoothChipVersion(void) {
    if (BluetoothSendReceive(const_cast<char*>(BT_VER), const_cast<char*>(AT_INSTRUCTION_OK)) == 0) {
        XAG_LOG_I("info : chip version read success.\n");
    } else {
        XAG_LOG_I("[[ error: chip version read fail...]]\r\n");
        return -1;
    }

    return 0;
}

/**
 * BluetoothSetUart - set uart.
 * @none
 */
int32_t BluetoothSetUart(void) {
    char pAtInstruction[BT_INSTRUCTION_LEN] = { 0 };

    snprintf(pAtInstruction, sizeof(pAtInstruction), BT_SET_UART, 115200, 8, 1, 0, 50);

    if (BluetoothSendReceive(const_cast<char*>(pAtInstruction), const_cast<char*>(AT_INSTRUCTION_OK)) == 0) {
        XAG_LOG_I("info : set uart success.\n");
    } else {
        XAG_LOG_I("[[ error: set uart fail...]]\r\n");
        return -1;
    }

    return 0;
}

/**
 * BluetoothGetSerinum - get serial number.
 * @none
 */
int32_t BluetoothGetSerinum(void) {
    if (BluetoothSendReceive(const_cast<char*>(BT_GET_SERINUM), const_cast<char*>(AT_INSTRUCTION_OK)) == 0) {
        XAG_LOG_I("info : get serial number success.\n");
    } else {
        XAG_LOG_I("[[ error: get serial number fail...]]\r\n");
        return -1;
    }

    return 0;
}

/**
 * bluetooth_get_sysid - get system id.
 * @none
 */
int32_t BluetoothGetSysid(void) {
    if (BluetoothSendReceive(const_cast<char*>(BT_SYSID), const_cast<char*>(AT_INSTRUCTION_OK)) == 0) {
        XAG_LOG_I("info : get system id success.\n");
    } else {
        XAG_LOG_I("[[ error: get system id fail...]]\r\n");
        return -1;
    }

    return 0;
}

/**
 * BluetoothGetAdevnStatus - 获取广播使能控制状态(ON|OFF).
 * @none
 */
int32_t BluetoothGetAdevnStatus(void) {
    if (BluetoothSendReceive(const_cast<char*>(BT_GET_ADVEN), const_cast<char*>(AT_INSTRUCTION_OK)) == 0) {
        XAG_LOG_I("info : get Broadcast enable control status success.\n");
    } else {
        XAG_LOG_I("[[ error: get Broadcast enable control status fail...]]\r\n");
        return -1;
    }

    return 0;
}

/**
 * BluetoothBroadcastData - 广播数据.
 * @none
 */
int32_t BluetoothBroadcastData() {
    char pAtInstruction[BT_INSTRUCTION_LEN] = { 0 };

    snprintf(pAtInstruction, sizeof(pAtInstruction), BT_SET_ADVDAT, "xag bluetooth message for test!!!!!!");

    if (BluetoothSendReceive(const_cast<char*>(pAtInstruction), const_cast<char*>(AT_INSTRUCTION_OK)) == 0) {
        XAG_LOG_I("info : Broadcast Data success.\n");
    } else {
        XAG_LOG_I("[[ error: Broadcast Data fail...]]\r\n");
        return -1;
    }

    return 0;
}

/**
 * BluetoothGetBroadcastChannel - 获取广播通道.
 * @none
 */
int32_t BluetoothGetBroadcastChannel(void) {
    if (BluetoothSendReceive(const_cast<char*>(BT_GET_BCCH), const_cast<char*>(AT_INSTRUCTION_OK)) == 0) {
        XAG_LOG_I("info : get Broadcast Channel success.\n");
    } else {
        XAG_LOG_I("[[ error: get Broadcast Channel fail...]]\r\n");
        return -1;
    }

    return 0;
}

/**
 * BluetoothSetBroadcastChannel - 设置广播通道.
 * @none
 */
int32_t BluetoothSetBroadcastChannel(void) {
    char pAtInstruction[BT_INSTRUCTION_LEN] = { 0 };

    snprintf(pAtInstruction, sizeof(pAtInstruction), BT_SET_BCCH, 6);

    if (BluetoothSendReceive(const_cast<char*>(pAtInstruction), const_cast<char*>(AT_INSTRUCTION_OK)) == 0) {
        XAG_LOG_I("info : set Broadcast Channel success.\n");
    } else {
        XAG_LOG_I("[[ error: set Broadcast Channel fail...]]\r\n");
        return -1;
    }

    return 0;
}

/**
 * BluetoothGetWorkMode - 获取蓝牙工作模式.
 * @none
 */
int32_t BluetoothGetWorkMode(void) {
    if (BluetoothSendReceive(const_cast<char*>(BT_GET_BLEMODE), const_cast<char*>(AT_INSTRUCTION_OK)) == 0) {
        XAG_LOG_I("info : get workmode success.\n");
    } else {
        XAG_LOG_I("[[ error: get workmode fail...]]\r\n");
        return -1;
    }

    return 0;
}

/**
 * BluetoothSetWorkMode - 设置蓝牙工作模式.
 * @none
 */
int32_t BluetoothSetWorkMode(int32_t sMode) {
    char pAtInstruction[BT_INSTRUCTION_LEN] = { 0 };

    snprintf(pAtInstruction, sizeof(pAtInstruction), BT_SET_BLEMODE, sMode);

    sdev->Write(pAtInstruction, strlen(pAtInstruction));
    usleep(10*1000);

    return 0;
}

/**
 * BluetoothChipReset - 蓝牙芯片重启.
 * @none
 */
int32_t BluetoothChipReset(void) {
    sdev->Write(BT_RESET, strlen(BT_RESET));
    usleep(10*1000);
    XAG_LOG_I("info : chip reset success.\n");

    return 0;
}

int32_t BluetoothBroadcastMode() {
    BluetoothAtMode();
    usleep(200*1000);
    BluetoothSetUart();
    usleep(200*1000);
    BluetoothGetWorkMode();
    usleep(200*1000);
    BluetoothSetWorkMode(MODE_BROADCAST);
    usleep(200*1000);
    BluetoothChipReset();
    usleep(2000*1000);

    return 0;
}

int32_t BluetoothTransparentModule_Impl::SendThread(void) {
    kapok_common_basic::SetThreadName("BluetoothTrans");
    int32_t s32SendCoutner = 0;

    string requestStr1 = R"({"cmd":32761,"code":0,"data":{"strCmd":"request1\n"},"msg":"ok"})";
    string requestStr2 = "{\"cmd\":32762,\"code\":0,\"data\":{\"strCmd\":\"request2\\n\"},\"msg\":\"ok\"}";

    auto ResponseCB1 = [&s32SendCoutner](void * context, xag_nav::os::Xap2Frame & fram, uint16_t errcode) {
            XAG_LOG_I("in ResponseCB1 %d", errcode);
            XAG_LOGF_I("This is a respond, form {}, to {}.", fram.from(),
                      fram.to());
            XAG_LOGF_I("context : {}", (char*)context);
            XAG_LOGF_I("errcode : {}", errcode);
            XAG_LOGF_I("sequence : {}", fram.sequence());
            XAG_LOGF_I("timestamp : {}", fram.timestamp());
            XAG_LOGF_I("timeout : {}", fram.timeout());
            XAG_LOGF_I("responsedata: {}", fram.data());
            /* uart send */
            sdev->Write(fram.data());
        };


    BluetoothAtMode();
    usleep(200*1000);
    BluetoothSetUart();
    usleep(200*1000);
    BluetoothChipReset();
    usleep(1000*1000);

    while (m_bRunning) {
        int ret = 0;
        int i = 0;
        char pRecvBuff[256] = {0};

        ret = sdev->Read(pRecvBuff, 256);
        if (ret > 0) {
            for (i = 0; i < ret; i++) {
                printf("%.2x ", pRecvBuff[i]);
            }
            printf("\n");
            XAG_LOG_I("--- uart receive [%d] ---", ret);

            if (ret > 2) {
                if (nullptr != m_spXnetComm) {
                    m_spXnetComm->SendXnetRequest(strServerName1, strServerName2,
                        pRecvBuff, ret, ResponseCB1, xag_nav::os::DataEncoding::EN_BINARY, 0x0017);
                }
            }
        } else {
            XAG_LOG_I("--- wait uart data ...");
        }

        usleep(100*1000);
    }

    return s32SendCoutner;
}

int32_t BluetoothTransparentModule_Impl::RegRecvCb(void) {
    int32_t s32RecvCoutnerMsg = 0;
    int32_t s32RecvCoutnerRequest = 0;

    XAG_LOG_I("--- BlueToothTransRecvThread Enter ...");

    auto RequestCallBack1 = [&s32RecvCoutnerRequest](xag_nav::os::Xap2Frame& frame, int errcd) {
        XAG_LOG_I("in RequestCallBack1 %d", errcd);
        // Xnet->PrintXapFrame(frame);
        s32RecvCoutnerRequest++;
        XAG_LOGF_I("requestdata: {}", frame.data());

        /* uart send */
        sdev->Write(frame.data());

        frame.setMethod(static_cast<uint32_t>(xag_nav::os::FrameType::TYPE_RESPOND));
        frame.setData("hello dls");
    };

    if (nullptr != m_spXnetComm) {
        m_spXnetComm->XnetUserResponseIfReg(strServerName1, strServerName2,
                xag_nav::os::DataEncoding::EN_BINARY, 0, 0, RequestCallBack1);
    }
    XAG_LOGF_I("total recv msg {}, request {}", s32RecvCoutnerMsg, s32RecvCoutnerRequest);

    return s32RecvCoutnerRequest + s32RecvCoutnerMsg;
}

int32_t BluetoothTransparentModule_Impl::UnRegRecvCb(void) {
    if (nullptr != m_spXnetComm) {
        m_spXnetComm->XnetUserResponseIfUnReg(strServerName1, strServerName2,
                        xag_nav::os::DataEncoding::EN_BINARY, 0, 0);
    }
    return 0;
}

BluetoothTransparentModule_Impl::BluetoothTransparentModule_Impl()
{}

BluetoothTransparentModule_Impl::~BluetoothTransparentModule_Impl()
{}

bool BluetoothTransparentModule_Impl::Init(void) {
    XAG_LOGF_I("BluetoothTransparentModule_Impl init ...");
    sdev = new XAG_SerialPort("/dev/ttyS3", 115200);
    if (sdev->Open() < 0) {
        delete sdev;
        return false;
    }

    sdev->SetTimeout(1000);

    /* 注册xnet回调 */
    RegRecvCb();
    m_bRunning = true;
    std::thread id(std::bind(&BluetoothTransparentModule_Impl::SendThread, this));
    m_thId = std::move(id);


    return true;
}

bool BluetoothTransparentModule_Impl::Uninit(void) {
    /* 注销xnet回调 */
    UnRegRecvCb();
    m_bRunning = false;
    m_thId.join();

    if (nullptr != sdev) {
        delete sdev;
    }
    return true;
}

bool BluetoothTransparentModule_Impl::SetXnetCommModule(
    std::shared_ptr<business_modules_xnetcomm::XnetCommModule> spXnetComm) {
    if (nullptr == spXnetComm) {
        XAG_LOG_E("sp xnet module is nullptr");
        return false;
    }

    m_spXnetComm = spXnetComm;
    return true;
}

bool BluetoothTransparentModule_Impl::BluetoothFactoryTest(void) {
    int ret = -1;

    ret = BluetoothGetSysid();
    if (ret == 0) {
        return true;
    } else {
        return false;
    }
}

} /* namespace business_modules_bluetoothtransparent */
